﻿using System.Collections.Concurrent;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using PmSoft;
using PmSoft.Caching;
using PmSoft.Utilities;

namespace PmSoft
{
    /// <summary>
    /// 实体元数据
    /// </summary>
    public class EntityData
    {
        private static ConcurrentDictionary<Type, EntityData> entityDatas;

        public EntityData(Type entityType, bool enableDistributedCache)
        {
            EnableDistributedCache = enableDistributedCache;
            Type = entityType;
            CacheSettingAttribute? attribute = entityType.GetCustomAttribute<CacheSettingAttribute>();
            if (attribute != null && !string.IsNullOrEmpty(attribute.Name))
                TypeHashID = attribute.Name;
            else
                TypeHashID = entityType.Name;// MD5(entityType.FullName ?? entityType.Name).ToLower();

            //对realTimeCacheHelper进行初始化
            if (!EnableDistributedCache)
            {
                EntityCache = ParseEntityCache();
            }
        }

        static EntityData()
        {
            entityDatas = new ConcurrentDictionary<Type, EntityData>();
        }

        /// <summary>
        /// 实体类型
        /// </summary>
        public Type Type { get; private set; }

        /// <summary>
        /// 类型的哈希值（16位md5） 
        /// </summary>
        public string TypeHashID { get; private set; }

        /// <summary>
        /// 是否启用了分布式缓存
        /// </summary>
        public bool EnableDistributedCache { get; private set; }

        /// <summary>
        /// 实体缓存版本信息
        /// </summary>
        public EntityCache EntityCache { get; private set; }

        /// <summary>
        /// 根据实体类型获取实体元数据
        /// </summary>
        /// <param name="type">实体类型</param>
        /// <param name="enableDistributedCache">是否启用了分布式缓存</param>
        /// <returns></returns>
        public static EntityData ForType(Type type, bool enableDistributedCache)
        {
            if (!entityDatas.TryGetValue(type, out EntityData? entityData) && entityData == null)
            {
                entityData = new EntityData(type, enableDistributedCache);
                entityDatas[type] = entityData;
            }
            return entityData;
        }

        /// <summary>
        /// 解析Type的CacheTimelinessHelper 
        /// </summary>
        /// <returns></returns>
        public EntityCache ParseEntityCache()
        {
            EntityCache? entityCache = null;
            object[] customAttributes = this.Type.GetCustomAttributes(typeof(CacheSettingAttribute), true);
            if (customAttributes.Length > 0)
            {
                CacheSettingAttribute? attribute = customAttributes[0] as CacheSettingAttribute;
                if (attribute != null)
                {
                    entityCache = new EntityCache(attribute.EnableCache, TypeHashID);
                    if (attribute.EnableCache)
                    {
                        switch (attribute.ExpirationPolicy)
                        {
                            case EntityCacheExpirationPolicies.Stable:
                                entityCache.CachingExpirationType = CachingExpirationType.Stable;
                                break;

                            case EntityCacheExpirationPolicies.Usual:
                                entityCache.CachingExpirationType = CachingExpirationType.UsualSingleObject;
                                break;

                            default:
                                entityCache.CachingExpirationType = CachingExpirationType.SingleObject;
                                break;
                        }
                        BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance;
                        List<EntityPropertyInfo> list = new List<EntityPropertyInfo>();
                        if (!string.IsNullOrEmpty(attribute.PropertyNamesOfArea))
                        {
                            foreach (string str in attribute.PropertyNamesOfArea.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                            {
                                PropertyInfo? property = this.Type.GetProperty(str, bindingFlags);
                                if (property != null)
                                    list.Add(property.AsEntityPropertyInfo());
                            }
                        }
                        entityCache.PropertiesOfArea = list;
                        if (!string.IsNullOrEmpty(attribute.PropertyNameOfBody))
                        {
                            PropertyInfo? propertyInfo = this.Type.GetProperty(attribute.PropertyNameOfBody, bindingFlags);
                            if (propertyInfo == null)
                                throw new ArgumentNullException(nameof(propertyInfo));
                            entityCache.PropertyNameOfBody = propertyInfo.AsEntityPropertyInfo();
                        }
                    }
                }
            }
            if (entityCache == null)
            {
                entityCache = new EntityCache(true, TypeHashID);
            }
            return entityCache;
        }




    }
}

